package std.game.objects.bodyparts;
import std.game.objects.trappings.AbstractWeapon;
import std.game.objects.trappings.Holdable;
import std.game.objects.trappings.Wearable;


import org.groovymud.object.MudObject;

import std.game.races.Statistics
import std.game.objects.containers.ContainerImpl
import org.groovymud.object.registry.InventoryHandler;
/**
 * Copyright 2008 Matthew Corby-Eaglen
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
 
class BodyPart extends ContainerImpl {
	
	boolean canHold = false
	
    def defences; // defences are cumulative
	def attacks; // attacks that you are not using but
	// still exist if unwielding items
	
	InventoryHandler linkedParts // for a pair of arms, legs, etc -
	// could be more than one linked!!
	def heldItem
	
	String partShortName
	
	public boolean checkCanAddItem(MudObject object) {
		if (object instanceof Wearable) {
			Wearable wearable = (Wearable) object;
			if (wearable.getNumberOfBodyPartsRequired() > 1 && linkedParts.size() < wearable.getNumberOfBodyPartsRequired() - 1) {
				return false;
			}
			// if the body part's names matched the items bodypartfor class
			// object then say yes
			if (wearable.getBodyPartNameFor() == name) {
				int containsAmount = getInventoryHandler().getMudObject(wearable.getBodyPartNameFor()).size();
				if (containsAmount < wearable.getMaxWearable()) {
					return super.checkCanAddItem(object);
				}
			}
		}
		return false;
	}
	
	public void addItem(MudObject object) {
		Wearable item = (Wearable) object;
		if (item.getNumberOfBodyPartsRequired() > 1) {
			HashSet<MudObject> linkedParts = getLinkedParts().getMudObjects();
			int amount = item.getNumberOfBodyPartsRequired();
			Iterator i = linkedParts.iterator();
			while (i.hasNext() && amount > 0) {
				BodyPart obj = (BodyPart) i.next();
				obj.addItem(object);
				amount--;
			}
		}
		super.addMudObject(object);
	}
	
	public MudObject removeItem(MudObject object) {
		HashSet<MudObject> linkedParts = getLinkedParts().getMudObjects();
		Iterator i = linkedParts.iterator();
		while (i.hasNext()) {
			BodyPart obj = (BodyPart) i.next();
			obj.removeItem(object);
		}
		return super.removeMudObject(object);
	}
	
	public boolean holdItem(Holdable item) {
		if (heldItem || !canHold) {
			return false;
		}
		
		
		return true; 
	}
	
	public def lowerItem() {
		def item = heldItem
		heldItem = null;
		return item;
	}
	
	Set getDefences() {
		Set defences = this.defences;
		if (holding) {
			Holdable item = getHeldItem();
			defences.addAll(item.getDefences());
		}
		Set wearing = getInventoryHandler().getItemsOfClass(Wearable.class);
		for (MudObject obj : wearing) {
			Wearable wearable = (Wearable) obj;
			defences.addAll(wearable.getDefences());
		}
		return defences;
	}
	
	
	Set getAttacks() {
		if (heldItem) {
			if (heldItem instanceof AbstractWeapon) {
				AbstractWeapon weapon = (AbstractWeapon) heldItem;
				return weapon.getAttacks();
			}
			// holding none weapons renders the limb useless
			return new HashSet();
		}
		return attacks;
	}
	
	Holdable getHeldItem() {
		return ((Holdable) heldItem.getMudObjects().toArray()[0]);
	}
	
	/**
	 * defers modding of character stats to worn/held items
	 * 
	 * @param moddedStats
	 */
	 def modifyStatistics(Statistics moddedStats) {
		if (holding) {
			Holdable item = getHeldItem();
			moddedStats = item.modifyStatistics(moddedStats);
		}
		inventoryHandler.mudObjects.each { obj ->
			moddedStatis = obj.modifyStatistics(moddedStats);
		}
		return moddedStats
	}
	
	InventoryHandler getLinkedParts() {
		if (linkedParts == null) {
			linkedParts = new InventoryHandler();
		}
		return linkedParts;
	}
	
	void setLinkedParts(def otherParts) {
		otherParts.each { part ->
			linkedParts.addMudObject(part);
		}
	}
	
}
